package com.mzj.saas.commons;

import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.config.SocketConfig;
import org.apache.http.impl.client.DefaultConnectionKeepAliveStrategy;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.TimeUnit;


public class HttpClientFactory {
	private static final Logger LOG = LoggerFactory.getLogger(HttpClientFactory.class);
	private static HttpAsyncClient httpAsyncClient = new HttpAsyncClient();
	private static HttpClientFactory httpClientFactory = new HttpClientFactory();

	private HttpClientFactory() {
	}

	private static PoolingHttpClientConnectionManager connectionManager;
	/**
	 * 请求配置
	 */
	private static final RequestConfig REQUEST_CONFIG = RequestConfig.custom().setConnectTimeout(3000)
			.setConnectionRequestTimeout(3000).setSocketTimeout(3000).setCircularRedirectsAllowed(true).build();

	public static HttpClientFactory getInstance() {

		return httpClientFactory;

	}

	public HttpAsyncClient getHttpAsyncClientPool() {
		return httpAsyncClient;
	}
	
	/**
	 * 创建连接池
	 * 
	 * @return
	 */
	private static synchronized PoolingHttpClientConnectionManager getConnectionManager() {
		if (connectionManager == null) {
			connectionManager = new PoolingHttpClientConnectionManager();
			initParam();
		}
		return connectionManager;
	}

	/**
	 * 初始化连接池参数
	 */
	private static void initParam() {
		SocketConfig socketConfig = SocketConfig.custom().setSoTimeout(3000).build();
		connectionManager.setDefaultSocketConfig(socketConfig);
		// 设置最大连接数
		connectionManager.setMaxTotal(500);
		// 每个路由基础连接数
		connectionManager.setDefaultMaxPerRoute(100);
		// 定时关掉连接池里面空闲或者过去的连接
		new Timer().scheduleAtFixedRate(new TimerTask() {
			@Override
			public void run() {
				// 关闭失效的连接
				connectionManager.closeExpiredConnections();
				// 可选的, 关闭30秒内不活动的连接
				connectionManager.closeIdleConnections(60, TimeUnit.SECONDS);
			}
		}, 1000 * 120L, 1000 * 120L);
	}

	/**
	 * 获取httpclient
	 * 
	 * @return
	 */
	public static HttpClient getHttpClient() {
		return HttpClients.custom().setConnectionManager(getConnectionManager())
				.setKeepAliveStrategy(new DefaultConnectionKeepAliveStrategy()).build();
	}

	/**
	 * 获取httpGet响应
	 * 
	 * @param url
	 * @return
	 * @throws Exception
	 */
	public static String doGet(String url) {
		HttpResponse response = null;
		HttpClient httpClient = getHttpClient();
		HttpGet get;
		try {
			get = getHttpGet(url);
		} catch (MalformedURLException | URISyntaxException e) {
			LOG.error(e.getMessage(), e);
			return null;
		}
		try {
			response = httpClient.execute(get);
			String data = EntityUtils.toString(response.getEntity());
			LOG.info("http url :" + url + ",status:" + response.getStatusLine().getStatusCode() + ",data:" + data);
			return data;
		} catch (Exception e) {
			LOG.error(e.getMessage(), e);
		}
		return null;
	}

	/**
	 * 获取httpGet
	 * 
	 * @param urlString
	 * @return
	 * @throws MalformedURLException
	 * @throws URISyntaxException
	 */
	public static HttpGet getHttpGet(String urlString) throws MalformedURLException, URISyntaxException {
		URL url = new URL(urlString);
		URI uri = new URI(url.getProtocol(), url.getHost(), url.getPath(), url.getQuery(), null);
		HttpGet get = new HttpGet(uri);
		get.setConfig(REQUEST_CONFIG);
		return get;

	}

	/**
	 * 获取httpPost响应
	 * 
	 * @param url
	 * @return
	 * @throws Exception
	 *             如果使用HttpPost方法提交HTTP
	 *             POST请求，则需要使用HttpPost类的setEntity方法设置请求参数。参数则必须用NameValuePair[]数组存储。
	 */
	public static HttpResponse doPost(String url, Map<String, Object> map) {
		HttpResponse response = null;
		HttpClient httpClient = getHttpClient();
		HttpPost post;
		try {
			post = getHttpPost(url);
		} catch (MalformedURLException | URISyntaxException e) {
			LOG.error(e.getMessage(), e);
			throw new CommonException("post url error");
		}
		List<NameValuePair> params = new ArrayList<>();
		for (Entry<String, Object> entry : map.entrySet()) {
			params.add(new BasicNameValuePair(entry.getKey(), (String) entry.getValue()));
		}
		try {
			post.setEntity(new UrlEncodedFormEntity(params, HTTP.UTF_8));
		} catch (UnsupportedEncodingException e) {
			LOG.error(e.getMessage(), e);
			throw new CommonException("post url encode error");
		}
		try {
			response = httpClient.execute(post);
		} catch (IOException e) {
			LOG.error(e.getMessage(), e);
			throw new CommonException("post io error");
		}
		return response;
	}

	/**
	 * 获取httpGet
	 * 
	 * @param urlString
	 * @return
	 * @throws MalformedURLException
	 * @throws URISyntaxException
	 */
	public static HttpPost getHttpPost(String urlString) throws MalformedURLException, URISyntaxException {
		URL url = new URL(urlString);
		URI uri = new URI(url.getProtocol(), url.getHost(), url.getPath(), url.getQuery(), null);
		HttpPost post = new HttpPost(uri);
		post.setConfig(REQUEST_CONFIG);
		return post;
	}

}
